vlwkaos' digital garden

Rust - HashMaps, Casting, If let, while let

if let and while let

  • Option할 때 None은 필요 없으니까 이런식으로 한다
fn main() {
    let my_vec = vec![2,3,4];
    let get_one = my_vec.get(0); // Option반환, 안전함
    let get_test = my_vec.get(10);

    println!("{:?}, {:?}", get_one, get_test); // Some(2), None

    // 아래 처럼 처리할 수도 있지만, 딱히 None에 대한 코드를 입력하고 싶지 않을 때 
    for index in 0..10 {
        match my_vec.get(index) {
            Some(number) => println!("{}", number),
            None => {}
        }
    }
    // let binding을 이용한다
    // if let 예시.
    for index in 0..10 {
        // 반환값에 대한 match를 하나에 한다
        if let Some(number) = my_vec.get(index) {
            println!("{}", number);
        }
    }

    // while let 예시
    let alpha_num_vec = vec![
        vec!["a", "b", "c", "1", "2"],
        vec!["d", "e", "f", "3", "4"],
    ];

    for mut alphanum in alpha_num_vec {
        println!("For {}: ", alphanum[0]);
        // 거꾸로 꺼낸다
        while let Some(i) = alphanum.pop() {
            // 에러에 대한 match test는 무시
            if let Ok(number) = i.parse::<i32>() {
                println!("Number: {}", number);
            }
        }
    }
}


HashMap

use std::collections::HashMap;
// HashMap<String, Vec<String>>
struct City {
    name: String,
    pop: HashMap<u32, u32> // year, pop
}

fn main() {

    let mut tallinn = City {
        name: "Tallinn".to_string(),
        pop: HashMap::new()
    };

    // 값이 없으면 None이 반환된다
    // 값이 있으면 이전 값이 반환된다. map의 값은 갱신된다.
    tallinn.pop.insert(1372, 1_000);
    tallinn.pop.insert(1373, 12_500);
    tallinn.pop.insert(1374, 234_000);

    // 안전하지 않음
    // println!("{:?}", tallinn.pop[&1372]);
    // 역시 get을 사용
    // 숫자는 borrowed reference로 해야함, HashMap에게 소유권을 주고싶지 않음.
    println!("{:?}", tallinn.pop.get(&1400)); // None
    if tallinn.pop.get(&1400).is_none() {
        tallinn.pop.insert(1400, 101_010);
    }
    //혹은
    if let Some(val) = tallinn.pop.get(&1400) {
        println!("has val");
    } else {
        tallinn.pop.insert(1400, 101_010);
    }
    

    // 순서가 보장되지 않는다. unordered map
    for (y, p) in tallinn.pop {
        println!("{}: {}", y, p);
    }

    
}

BTreeMap

  • 느리지만 ordered map
use std::collections::BTreeMap;

struct City {
    name: String,
    pop: BTreeMap<u32, u32> // year, pop
}

fn main() {

    let mut tallinn = City {
        name: "Tallinn".to_string(),
        pop: BTreeMap::new()
    };

    
    tallinn.pop.insert(1400, 123_123);
    tallinn.pop.insert(1372, 1_000);
    tallinn.pop.insert(1373, 12_500);
    tallinn.pop.insert(1374, 234_000);

    // key 값으로 정렬됨
    for (y, p) in tallinn.pop {
        println!("{}: {}", y, p); // 1372, 1373, 1374, 1400
    }
}

HashMap entry method

use std::collections::HashMap;

fn main() {
    let book_collection = vec![
        "A",
        "B",
        "C",
        "D",
    ];
    let mut book_hmap = HashMap::new();

    for book in book_collection {
        // 안좋은 예시. 있으면 넣고, 없으면 true
        // book_hmap.entry(book).or_insert(true);
        // Entry Vacant, Occupied
        // or_insert를 하면 mutable reference를 반환
        let no_of_books = book_hmap.entry(book).or_insert(0);
        *no_of_books += 1; // 없으면 0으로 초기화 + 저장된 값을 increment할 수 있다.
    }

    for (book, true_or_false) in book_hmap {
        println!("Do we have {}? {}", book, true_or_false);
    }
}

추가 예시

use std::collections::HashMap;

fn main() {

    let data = vec![
        ("male", 9),
        ("female", 8),
        ("male", 4),
        ("female", 1),
        ("male", 9),
        ("female", 5),
        ("male", 6),
    ];

    let mut survey_hash = HashMap::new();
    // 혹은 (gender, number)로 destructuring
    for item in data {
        // mutable이니까 만들어진 vec에 바로 넣을 수 있음
        survey_hash.entry(item.0).or_insert(Vec::new()).push(item.1);
    }

    for (male_or_female, numbers) in survey_hash {
        println!("{:?}, {:?}", male_or_female, numbers);
    }
}

Set

  • HashSet - UnorderedSet
  • BTreeSet - OrderedSet
  • insert시 반환값은 있는지 없는지 bool
use std::collections::HashSet;

fn main() {
    let many_numbers = vec![
        94, 42, 59, 64, 32, 22, 38, 5, 59, 49, 15, 89, 74, 29, 14, 68, 82, 80, 56, 41, 36, 81, 66,
        51, 58, 34, 59, 44, 19, 93, 28, 33, 18, 46, 61, 76, 14, 87, 84, 73, 71, 29, 94, 10, 35, 20,
        35, 80, 8, 43, 79, 25, 60, 26, 11, 37, 94, 32, 90, 51, 11, 28, 76, 16, 63, 95, 13, 60, 59,
        96, 95, 55, 92, 28, 3, 17, 91, 36, 20, 24, 0, 86, 82, 58, 93, 68, 54, 80, 56, 22, 67, 82,
        58, 64, 80, 16, 61, 57, 14, 11];

    let mut number_hashset = HashSet::new();

    for number in many_numbers {
        number_hashset.insert(number);
    }

    let hashset_length = number_hashset.len(); 
    println!("There are {} unique numbers, so we are missing {}.", hashset_length, 100 - hashset_length);

    // 1부터 100까지 없는 숫자 찾기
    let mut missing_vec = vec![];
    for number in 0..100 {
        //if number_hashset.get(&number).is_none() { // If .get() returns None,
        //    missing_vec.push(number);
        //}

        // if let binding사용해보기
        if let None = number_hashset.get(&number) {
            missing_vec.push(number);
        }
    }

    print!("It does not contain: ");
    for number in missing_vec {
        print!("{} ", number);
    }
}

BinaryHeap

use std::collections::BinaryHeap;

// heap에 남아있는 숫자 반환
// 나중에 iterator쓰는게 더 나은 방법이지만 일단 이렇게..
fn show_remainder(input: &BinaryHeap<i32>) -> Vec<i32> { 
    let mut remainder_vec = vec![];
    for number in input {
        remainder_vec.push(*number)
    }
    remainder_vec
}

fn main() {
    let many_numbers = vec![0, 5, 10, 15, 20, 25, 30]; 
    let mut my_heap = BinaryHeap::new();

    for number in many_numbers {
        my_heap.push(number);
    }

    // Option
    while let Some(number) = my_heap.pop() { 
        println!("Popped off {}. Remaining numbers are: {:?}", number, show_remainder(&my_heap));
    }

    // max heap
    let mut jobs = BinaryHeap::new();
    jobs.push((100, "A"));
    jobs.push((80, "B"));
    // jobs.peak() 값만 read
}

If let binding

let s = Some('c');

match s {
    Some(i) => println!("{}", i), // c
    _ => {}
}

// 변수 s가 옵션(Some)에 매칭 되는가? 를 한줄로, 그러나 if else 원칙
if let Some(i) = s {
    println!("{}", i); // c
}

while let binding

loop 예제

let mut s = Some(0);

loop {
    match s {
        Some(i) => if i > 19 {
            println!("Quit");
            s = None;
        } else {
            println!("{}", i);
            s = Some(i + 2);
        },
        _ => {
            break;
        }
    }
}

// 위랑 동일함. destructuring pattern matching
while let Some(i) = s {
    if i > 19 {
        println!("Quit");
        s = None;
    } else {
        println!("{}", i);
        s = Some(i + 2);
    },
}

Casting

let f = 24.4313214;
let i = f as u8; // 24
let c = i as char // .

Referred in

Rust - HashMaps, Casting, If let, while let